﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GMUtilitiesDotNet.Gestures;
using System.Windows.Input;
using System.Windows;
using ThouShaltNotBrickLevelEditor.Code.GeneralObjects;
using ThouShaltNotBrickLevelEditor.Code.Helpers;
using GMUtilitiesDotNet.Helpers;

namespace ThouShaltNotBrickLevelEditor.Gestures
{
    public sealed class AddBrickGesture : GestureBase
    {
        #region Properties
        private bool mIsDragging;
        private BrickPosition mLastBrickPosition;
        #endregion

        #region Constructors
        public AddBrickGesture()
        {
            Handled = false;
            ClearData();
        }
        #endregion

        #region Overriden Methods
        public override bool OnMouseLeftButtonDown(MouseButtonEventArgs pArgs)
        {
            IInputElement inputElement = pArgs.Source as IInputElement;
            if (inputElement == null)
            {
                ClearData();
                return false;
            }

            mIsDragging = true;

            Point position = pArgs.GetPosition(inputElement);
            BrickPosition brickPosition = GetBrickPosition(position);

            if (ShouldSendUpdate(mLastBrickPosition, brickPosition))
            {
                mLastBrickPosition = brickPosition;
                CommandParam = brickPosition;
                return true;
            }
            else
            {
                mLastBrickPosition = brickPosition;
                CommandParam = brickPosition;
                return false;
            }
        }

        public override bool OnMouseLeftButtonUp(MouseButtonEventArgs pArgs)
        {
            IInputElement inputElement = pArgs.Source as IInputElement;
            if (inputElement == null)
            {
                ClearData();
                return false;
            }

            if (mIsDragging)
            {
                mIsDragging = false;

                Point position = pArgs.GetPosition(inputElement);
                BrickPosition brickPosition = GetBrickPosition(position);
                
                if (ShouldSendUpdate(mLastBrickPosition, brickPosition))
                {
                    mLastBrickPosition = brickPosition;
                    CommandParam = brickPosition;
                    return true;
                }
                else
                {
                    ClearData();
                    return false;
                }
            }
            else
            {
                ClearData();
                return false;
            }
        }

        public override bool OnMouseMove(MouseEventArgs pArgs)
        {
            IInputElement inputElement = pArgs.Source as IInputElement;
            if (inputElement == null)
            {
                ClearData();
                return false;
            }

            if (mIsDragging)
            {
                Point position = pArgs.GetPosition(inputElement);
                BrickPosition brickPosition = GetBrickPosition(position);

                if (ShouldSendUpdate(mLastBrickPosition, brickPosition))
                {
                    mLastBrickPosition = brickPosition;
                    CommandParam = brickPosition;
                    return true;
                }
                else
                {
                    mLastBrickPosition = brickPosition;
                    CommandParam = brickPosition;
                    return false;
                }
            }
            else
            {
                ClearData();
                return false;
            }
        }
        #endregion

        #region Methods
        private void ClearData()
        {
            mIsDragging = false;
            mLastBrickPosition = null;
            CommandParam = null;
        }

        private static BrickPosition GetBrickPosition(Point pMousePosition)
        {
            if (pMousePosition.X > Constants.LEVEL_WIDTH ||
                pMousePosition.Y > Constants.LEVEL_HEIGHT)
            {
                return null;
            }

            int row = (int)((Constants.LEVEL_HEIGHT - pMousePosition.Y) / Constants.BRICK_HEIGHT);
            row = MathHelpers.GetLimitedInt(row, 0, Constants.BRICK_ROWS - 1);

            int column = (int)(pMousePosition.X / Constants.BRICK_WIDTH);
            column = MathHelpers.GetLimitedInt(column, 0, Constants.BRICK_COLUMNS - 1);

            return new BrickPosition(row, column);
        }

        private static bool ShouldSendUpdate(
            BrickPosition pOldBrickPosition,
            BrickPosition pNewBrickPosition)
        {
            if (pNewBrickPosition != null)
            {
                if (pOldBrickPosition == null ||
                    pNewBrickPosition.Row != pOldBrickPosition.Row ||
                    pNewBrickPosition.Column != pOldBrickPosition.Column)
                {
                    return true;
                }
            }
            
            return false;
        }
        #endregion
    }
}